Wer im Telefonbuch sucht, kann drei Suchstrategien einsetzen:
Er weiss, auf welcher Seite sich ein Eintrag befindet und springt direkt auf diese Seite.
Er kennt zwar die Telefonnummer, weiss aber den Namen des Inhabers nicht. Er muss deshalb alle Einträge hintereinander durchzugehen.
Er kennt den Namen eines Nummerninhabers. Um die Nummer zu ermitteln, durchsucht er das Telefonbuch nach dem Prinzip des binären Suchens. Weil alle Namen alphabetisch sortiert sind, kann er den gesuchten Inhaber durch alphabetische Vergleiche solange einkreisen, bis er ihn gefunden hat. Wenn er zum Beispiel den Namen "Keller" sucht, dann weiss er, dass er in der ersten Telefonbuchhälfte suchen muss. Diese Hälfte kann er wiederum halbieren und in der richtigen Hälfte weitersuchen etc.
Die folgende Tabelle fasst die drei Suchstrategien zusammen und nennt ihre Vor- und Nachteile. Eine schnelle Suchstrategie stellt grössere Anforderungen an die Organisation der Daten und an das Vorwissen des Benutzers:
| Suche | Suchbeispiel | Bedingung | Effizienz |
| direkt | Seite 143 | Seiten nummeriert | sehr schnell |
| sequentiell | 061 / 422 13 07 | keine | langsam |
| binär | Bohnenblust Fritz | Einträge sortiert | schnell |
Ein konventionelles Telefonbuch ist ähnlich wie ein Datenfeld organisiert. Eine Seite entspricht einer Zelle, und eine Seitennummer entspricht dem Index. Wir bilden deshalb die drei Suchstrategien auf unser Datenfeld Läufer ab.
Direkt suchen heisst mit einem gegebenen Indexwert ein Feldelement bestimmen. Wenn zum Beispiel nach dem Namen des dritten Läufers gefragt wird, so lautet die Antwort:
Name = Läufer(3)
Sequentiell suchen heisst hintereinander jedes Element mit einem Suchwert vergleichen, bis die Suche Erfolg hat. Wenn zum Beispiel nach der Nummer der Läuferin Dora gefragt wird, so lautet die Antwort: Vergleiche der Reihe nach alle Elemente, bis die Nummer auftaucht:
For Nummer = 1 To 5 If Läufer(Nummer) = “Dora” Then MsgBox “Nummer von Dora = ” & Nummer Exit For End If Next Nummer
Die Zählschleife (For ... Next) geht solange von Zelle zu Zelle, bis der Inhalt des laufenden Elements mit Dora übereinstimmt. Dann wird in einem Ausgabefeld Nummer von Dora = und die gefundene Nummer ausgegeben (& verknüpft die Stringkonstante mit Nummer und konvertiert dabei die Zahl Nummer automatisch in einen String). Weil die Suche nun beendet ist, verlässt die Anweisung Exit For die Zählschleife. Wir erweitern deshalb die Syntax der Zählschleife:
Dim Index As Integer
For Index = <Untergrenze> To <Obergrenze>
<Anweisungen>
[Exit For]
<Anweisungen>]
Next Index
Exit For steht in eckigen Klammern, weil es weggelassen werden kann, falls die Schleife nicht mitten im Schleifenkörper verlassen werden muss.
Schreiben Sie die sequentielle Suche b) mit einer
While-Schleife.
Wer im Telefonbuch binär sucht, ...
springt in die Mitte
schaut, ob der Suchwert in der linken oder rechten Hälfte liegt
Eine solche Suche heisst Binärsuche. Sie halbiert ein sortiertes Datenfeld solange, bis das gesuchte Element gefunden wird. Bevor wir die Binärsuche in VBA ausdrücken, beschreiben wir sie entwurfssprachlich. Wir verwenden dazu das Datenfeld Läufer und starten mit dem Beispielaufruf ...
sucheBinär(1,7, "Paul", 4)
Das erste Argument enthält die Untergrenze des zu durchsuchenden Feldbereichs. Beim ersten Aufruf von sucheBinär deckt der Feldbereich noch das ganze Datenfeld Läufer ab Spätere Aufrufe durchsuchen einen immer kleineren Teil. Beim ersten Aufruf ist deshalb die Obergrenze 7. Das dritte Argument entspricht dem Suchwert “Paul” und das vierte Argument nennt die Mitte des Feldbereichs. Vor dem ersten Aufruf ist die Mitte (1 + 7) / 2 = 4. Vor jedem weiteren Aufruf wird die Mitte neu berechnet.
Die folgende Tabelle erweitert unser Läuferbeispiel um die Zellen 6 und 7 und zeigt in den Schritten 1 bis 3 die binäre Suche nach “Paul”:
|
Nr |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
|
Läufer(Nr) |
ANNA |
BRUNO |
DORA |
FRANZ |
KARIN |
NORA |
PAUL |
|
Schritt (1) |
L |
|
|
M |
|
|
R |
|
Schritt (2) |
|
|
|
|
L |
M |
R |
|
Schritt (3) |
|
|
|
|
|
|
L, M, R |
Links Indexwert der Untergrenze des jeweils betrachteten Feldbereichs
Mitte Indexwert der Mitte des jeweils betrachteten Feldbereichs
Rechts Indexwert der Obergrenze des jeweils betrachteten Feldbereichs
Gesucht sei die Startnummer von Paul. In der Tabelle erkennen Sie sofort das Suchergebnis 7. Weil der Computer nicht über die menschliche Fähigkeit des unmittelbaren Erkennens von Mustern verfügt, müssen wir ihm die Binärsuche schrittweise beibringen (Schritt in Klammern):
Zuerst ermittelt der Algorithmus aus den Positionsindizes Links und Rechts den Index Mitte (1). Weil der Läufer der Position Mitte (Franz) nicht gleich Paul ist, sucht der Algorithmus weiter. Paul ist alphabetisch grösser als Franz. Deshalb wird der rechte Teil des Datenfelds weiter untersucht: Die neue Mitte berechnet sich wieder aus Links und Rechts (2). Die Läuferin an der neuen Position von Mitte heisst Nora und ist ebenfalls kleiner als Paul. Weil jetzt der rechte Teil des Datenfelds nur noch aus einer einzigen Zelle besteht, fallen die Positionen Links, Rechts und Mitte zusammen und der Läufer an der Position Mitte entspricht dem Suchwert Paul (3).
Der verbalen Beschreibung entspricht der folgende entwurfssprachliche Algorithmus. Wir gehen wiederum von gleichen Aufruf aus:
sucheBinär(1,7, "Paul", 4)
sucheBinär(links,rechts, Name, Mitte) Mitte = (links + rechts) \ 2 ‘ganzzahlige Division Falls links <= Mitte dann Falls Name = Feld(Mitte) dann Name gefunden sonst Falls Name < Feld(Mitte) dann sucheBinär(links,Mitte-1, Name, Mitte) sonst Name > Feld(Mitte) sucheBinär(Mitte+1,rechts, Name, Mitte) sonst Name nicht gefunden
Der Rückwärtsstrich-Operator \ hinterlässt den ganzzahligen Anteil der Gleitkommadivision /. Zum Beispiel ergibt 5 \ 2 statt der Gleitkommazahl 2.5 die Ganzahl 2. Der Algorithmus ruft sich je nach Bedingung mit einer der fett gedruckten Anweisungen selbst wieder auf. Er heisst deshalb rekursiv (von lat. recurrere = zurücklaufen). Die folgende Geschichte veranschaulicht den Grundgedanken der Rekursion:
Ein Hund kam in die Küche und stahl dem Koch ein Ei,
da nahm der Koch den Löffel und schlug den Hund entzwei,
da kamen viele Hunde und gruben ihm ein Grab und setzten ihm einen Grabstein, worauf geschrieben stand:
Ein Hund kam in die Küche und stahl dem Koch ein Ei,
da nahm der Koch den Löffel und schlug den Hund entzwei,
da kamen viele Hunde und gruben ihm ein Grab und setzten ihm einen Grabstein, worauf geschrieben stand:
...
Diese Geschichte ist rekursiv, weil sie sich selbst aufruft, indem sie auf die vorangehende Geschichte zurückspringt. Die Katze beisst sich also in den Schwanz. Im Gegensatz zu dieser Hundegeschichte ist aber sucheBinär endlich rekursiv. Ein endlich rekursives Programm ruft sich nur solange auf, bis eine Endbedingung erfüllt wird. In unserem Fall ist die Endbedingung dann erfüllt, wenn der Name auf der Position Mitte gleich dem gesuchten Namen ist.
Wenn Sie auf die Startschaltfläche von sucheBinär.xls klicken, dann erscheint ein Eingabefeld, das Sie nach einem gross geschriebenen Suchnamen - zum Beispiel NORA - frägt (siehe Bild unten). Die gefundene Zellnummer wird dann in einem Ausgabefeld angezeigt, andernfalls erscheint die Fehlermeldung Kein Element mit diesem Wert. Ereignisprozedur der Schaltfläche »Suche binär ist die Subroutine sucheBinär() (siehe Code unten).
Damit das Datenfeld Läufer sowohl in der Subroutine sucheBinär() als auch in der aufgerufenden Funktion gefunden gelesen werden kann, vereinbaren wir es mit Private (statt Dim). So ist es im ganzen Modul, und nicht nur in einer bestimmten Prozedur, bekannt:
Private Läufer(1 To 7) As String
Besser wäre allerdings eine Vereinbarung von Läufer in der Subroutine sucheBinär() und eine Übergabe des Datenfelds Läufer als Argument an die Funktion gefunden:
If gefunden(Läufer, 1,7, Suchname, Nr) = True Then ...
Datenfelder wie Läufer können aber in einzelnen Programmiersprachen, insbesondere in älteren Versionen von Visual Basic, keine Argumente von Prozeduren sein. Wir belassen es deshalb bei der Private-Vereinbarung.
Die folgenden Abbildungen zeigen die Anwender- und Entwicklersicht der Binärsuche. gefunden(links,rechts, Läufername, Mitte) ist eine boolsche Funktion, welche die entwurfssprachliche Version der Binärsuche implementiert. Sie ergibt True, falls der Suchname im Datenfeld vorkommt, sonst False. Die Nummer der gefundenen Zelle wird als Argument Mitte zurückgegeben.
Anwendersicht der Arbeitsmappe sucheBinär.xls
Sub sucheBinaer() Dim Nr As Integer, Suchname As String Läufer(1) = “ANNA” Läufer(2) = “BRUNO” Läufer(3) = “DORA” Läufer(4) = “FRANZ” Läufer(5) = “KARIN” Läufer(6) = “NORA” Läufer(7) = “PAUL” Suchname = InputBox(“Name in Grossbuchstaben: ”) If gefunden(1,7, Suchname, Nr) = True Then MsgBox “Gesuchte Nummer = ” & Nr ElseIf Suchname <> “” ‘ kein Klick auf “Abbrechen” MsgBox “Kein Element mit diesem Wert” End If End Sub
Ereignisprozedur der Schaltfläche ‘Suche binär’
Function gefunden( _
links As Integer, _
rechts As Integer, _
Läufername As String, _
Mitte As Integer) As Boolean
Mitte = (links + rechts) \ 2 ‘ Mitte gibt die gefundene Läufernummer zurück
If links <= Mitte Then
If Läufername = Läufer(Mitte) Then
gefunden = True
Else
If Läufername < Läufer(Mitte) Then
gefunden = gefunden(links, Mitte-1, Läufername, Mitte)
Else
gefunden = gefunden(Mitte+1, rechts, Läufername, Mitte)
End If
End If
Else
gefunden = False
End If
End Function
Binärsuche als VBA-Funktion
![]()
Rekursion in einem Installationsskript
(veranschaulicht die praktische Anwendung der Rekursion)